package com.atguigu.tingshu.payment.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.account.client.RechargeInfoFeignClient;
import com.atguigu.tingshu.common.constant.KafkaConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.service.KafkaService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.account.RechargeInfo;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.order.client.OrderInfoFeignClient;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Resource
    private OrderInfoFeignClient orderInfoFeignClient;

    @Autowired
    private WxPayV3Config wxPayV3Config;

    @Autowired
    private JsapiServiceExtension jsapiServiceExtension;

    @Resource
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private NotificationParser parser;

    @Autowired
    private KafkaService kafkaService;

    @Resource
    private RechargeInfoFeignClient rechargeInfoFeignClient;


    @Override
    public Map<String, String> createJsapi(String itemType, String orderNo) {
        Long userId = AuthContextHolder.getUserId();
        OrderInfo orderInfo = null;
        RechargeInfo rechargeInfo = null;
        if (SystemConstant.PAYMENT_TYPE_ORDER.equals(itemType)) {
            //查询订单信息
            Result<OrderInfo> orderInfoResult = this.orderInfoFeignClient.getOrderInfo(orderNo);
            Assert.notNull(orderInfoResult, "生成预支付订单：获取订单信息失败！");
            orderInfo = orderInfoResult.getData();
            Assert.notNull(orderInfo, "生成预支付订单：获取订单信息失败！");
            //判断支付状态
            if (SystemConstant.ORDER_STATUS_PAID.equals(orderInfo.getOrderStatus())) {
                throw new RuntimeException("该订单已支付");
            }
            //判断订单的拥有者
            if (!userId.equals(orderInfo.getUserId())) {
                throw new RuntimeException("该订单被篡改");
            }
        } else if (SystemConstant.PAYMENT_TYPE_RECHARGE.equals(itemType)) {
            //查询充值信息
            Result<RechargeInfo> rechargeInfoResult = this.rechargeInfoFeignClient.getRechargeInfo(orderNo);
            Assert.notNull(rechargeInfoResult, "生成预支付订单，获取充值信息失败！");
            rechargeInfo = rechargeInfoResult.getData();
            Assert.notNull(rechargeInfoResult, "生成预支付订单，获取充值信息失败！");
            //判断支付状态
            if (SystemConstant.ORDER_STATUS_PAID.equals(rechargeInfo.getRechargeStatus())) {
                throw new RuntimeException("该订单已支付");
            }
            //判断订单的拥有者
            if (!userId.equals(rechargeInfo.getUserId())) {
                throw new RuntimeException("该订单被篡改");
            }
        }
        //调用第三方接口  配置预支付参数
        PrepayRequest request = new PrepayRequest();
        request.setAppid(wxPayV3Config.getAppid());
        request.setMchid(wxPayV3Config.merchantId);
        request.setDescription("谷粒随享支付平台");
        request.setOutTradeNo(orderNo);
        Amount amount = new Amount();
        amount.setTotal(1);
        request.setAmount(amount);
        //根据userId查询用户信息表
        Result<UserInfo> userInfoResult = this.userInfoFeignClient.findUserById(userId);
        Assert.notNull(userInfoResult, "配置预支付参数：获取用户信息失败！");
        UserInfo userInfo = userInfoResult.getData();
        Assert.notNull(userInfo, "配置预支付参数：获取用户信息失败！");
        Payer payer = new Payer();
        payer.setOpenid(userInfo.getWxOpenId());
        request.setPayer(payer);
        request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
        PrepayWithRequestPaymentResponse response = jsapiServiceExtension.prepayWithRequestPayment(request);

        //返回给小程序客户端
        Map<String, String> map = new HashMap();
        map.put("timeStamp", response.getTimeStamp());
        map.put("nonceStr", response.getNonceStr());
        map.put("package", response.getPackageVal());
        map.put("signType", response.getSignType());
        map.put("paySign", response.getPaySign());

        //保存支付流水
        if (SystemConstant.PAYMENT_TYPE_ORDER.equals(itemType)) {
            this.savePaymentInfo(orderInfo);
        } else if (SystemConstant.PAYMENT_TYPE_RECHARGE.equals(itemType)) {
            this.savePaymentInfo(rechargeInfo);
        }
        return map;
    }

    @Override
    public Map<String, String> notifyFunction(HttpServletRequest request) {
        //创建返回集合
        Map<String, String> map = new HashMap<>();
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(request.getHeader("Wechatpay-Seria"))
                .nonce(request.getHeader("Wechatpay-Nonce"))
                .signature(request.getHeader("Wechatpay-Signature"))
                .timestamp(request.getHeader("Wechatpay-Timestamp"))
                .body(PayUtil.readData(request))
                .build();
        try {
            // 以支付通知回调为例，验签、解密并转换成 Transaction
            Transaction transaction = parser.parse(requestParam, Transaction.class);
            //失败
            if (!Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
                map.put("code", "FAIL");
                map.put("message", "失败");
                return map;
            }
            //成功
            //更新订单状态
            this.updatePaymentInfo(transaction);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return map;
    }

    @Override
    public Boolean queryPayStatus(String orderNo) {
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(wxPayV3Config.getMerchantId());
        queryRequest.setOutTradeNo(orderNo);
        try {
            Transaction transaction = jsapiServiceExtension.queryOrderByOutTradeNo(queryRequest);
            if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    private void savePaymentInfo(OrderInfo orderInfo) {
        //查询是否存在记录
        PaymentInfo payment = this.paymentInfoService.getOne(new LambdaQueryWrapper<PaymentInfo>()
                .eq(PaymentInfo::getOrderNo, orderInfo.getOrderNo()));
        if (payment != null) {
            return;
        }
        PaymentInfo paymentInfo = new PaymentInfo();
        paymentInfo.setUserId(orderInfo.getUserId());
        paymentInfo.setPaymentType(SystemConstant.PAYMENT_TYPE_ORDER);
        paymentInfo.setOrderNo(orderInfo.getOrderNo());
        paymentInfo.setPayWay(orderInfo.getPayWay());
        paymentInfo.setAmount(orderInfo.getOrderAmount());
        paymentInfo.setContent(orderInfo.getOrderTitle());
        paymentInfo.setPaymentStatus(SystemConstant.PAYMENT_STATUS_UNPAID);
        this.paymentInfoService.save(paymentInfo);
    }

    private void savePaymentInfo(RechargeInfo rechargeInfo) {
        //查询是否存在记录
        PaymentInfo payment = this.paymentInfoService.getOne(new LambdaQueryWrapper<PaymentInfo>()
                .eq(PaymentInfo::getOrderNo, rechargeInfo.getOrderNo()));
        if (payment != null) {
            return;
        }
        PaymentInfo paymentInfo = new PaymentInfo();
        paymentInfo.setUserId(rechargeInfo.getUserId());
        paymentInfo.setPaymentType(SystemConstant.PAYMENT_TYPE_RECHARGE);
        paymentInfo.setOrderNo(rechargeInfo.getOrderNo());
        paymentInfo.setPayWay(rechargeInfo.getPayWay());
        paymentInfo.setAmount(rechargeInfo.getRechargeAmount());
        paymentInfo.setContent("余额充值");
        paymentInfo.setPaymentStatus(SystemConstant.PAYMENT_STATUS_UNPAID);
        this.paymentInfoService.save(paymentInfo);
    }

    private void updatePaymentInfo(Transaction transaction) {
        PaymentInfo info = this.paymentInfoService.getOne(new LambdaQueryWrapper<PaymentInfo>()
                .eq(PaymentInfo::getOrderNo, transaction.getOutTradeNo()));
        if (info == null) {
            return ;
        }
        info = new PaymentInfo();
        info.setPaymentStatus(SystemConstant.PAYMENT_STATUS_PAID);
        info.setOutTradeNo(transaction.getTransactionId());
        info.setCallbackTime(new Date());
        info.setCallbackContent(JSON.toJSONString(transaction));
        if(this.paymentInfoService.updateById(info)){
            if (SystemConstant.PAYMENT_TYPE_ORDER.equals(info.getPaymentType())) {
                this.kafkaService.sendMsg(KafkaConstant.QUEUE_ORDER_PAY_SUCCESS, transaction.getOutTradeNo());
            } else if (SystemConstant.PAYMENT_TYPE_RECHARGE.equals(info.getPaymentType())) {
                //更新充值记录
                this.kafkaService.sendMsg(KafkaConstant.QUEUE_ORDER_PAY_SUCCESS, transaction.getOutTradeNo());
            }
        }
    }
}
